# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# openUBMC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#         http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.

# -*- coding: utf-8 -*-
"""
Lambda 和 TypeVar 代码生成测试
"""

import pytest
from tests.pytests.helpers.codegen_helpers import compile_source, assert_code_contains


# ============================================================================
# 基础 Lambda 表达式测试
# ============================================================================


def test_simple_lambda_code_generation():
    """测试简单 lambda 的完整代码生成"""

    code = """
def use_lambda() -> int:
    square = lambda x: x * x
    return square(5)
"""

    hpp, cpp = compile_source(code)

    header_pattern = """
    struct __lambda_${w+}_${d+}_${d+}
        : public mcpy::lambda_base<__lambda_${w+}_${d+}_${d+}, mc::variant(mc::variant)> {
        static constexpr std::array<const char*, 1> get_param_names() {
            return {"x"};
        }
        template <typename T0>
        auto operator()(T0&& x) const {
            return x * x;
        }
    };
    """
    assert_code_contains(hpp, header_pattern, use_markers=True)

    cpp_pattern = """
    int use_lambda() {
        __lambda_${w+}_${d+}_${d+} square;
        return mcpy::cast<int>(square(5));
    }
    """
    assert_code_contains(cpp, cpp_pattern, use_markers=True)


def test_lambda_multi_params():
    """测试多参数 lambda"""

    code = """
def use_binary():
    add = lambda x, y: x + y
    return add(3, 4)
"""

    hpp, cpp = compile_source(code)

    header_pattern = """
    struct __lambda_${w+}_${d+}_${d+}
        : public mcpy::lambda_base<__lambda_${w+}_${d+}_${d+}, mc::variant(mc::variant, mc::variant)> {
        static constexpr std::array<const char*, 2> get_param_names() {
            return {"x", "y"};
        }
        template <typename T0, typename T1>
        auto operator()(T0&& x, T1&& y) const {
            return x + y;
        }
    };
    """
    assert_code_contains(hpp, header_pattern, use_markers=True)

    cpp_pattern = """
    mc::variant use_binary() {
        __lambda_${w+}_${d+}_${d+} add;
        return add(3, 4);
    }
    """
    assert_code_contains(cpp, cpp_pattern, use_markers=True)


def test_lambda_closure_capture():
    """测试闭包捕获"""

    code = """
def make_counter(start: int):
    return lambda: start + 1
"""

    hpp, cpp = compile_source(code)

    header_pattern = """
    struct __lambda_${w+}_${d+}_${d+}
        : public mcpy::lambda_base<__lambda_${w+}_${d+}_${d+}, int()> {
        int start;
        __lambda_${w+}_${d+}_${d+}(int start_)
            : start(std::move(start_)) {
        }
        auto operator()() const {
            return start + 1;
        }
    };
    """
    assert_code_contains(hpp, header_pattern, use_markers=True)

    cpp_pattern = """
    mc::variant make_counter(int start) {
        return mc::variant(mc::make_shared<__lambda_${w+}_${d+}_${d+}>(start));
    }
    """
    assert_code_contains(cpp, cpp_pattern, use_markers=True)


def test_lambda_in_list_storage():
    """测试 lambda 在列表中的存储"""

    code = """
def get_funcs():
    return [lambda x: x + 1, lambda x: x * 2]
"""

    hpp, cpp = compile_source(code)

    # 验证头文件：包含两个 lambda 结构体
    lambda_count = hpp.count("struct __lambda_")
    assert lambda_count >= 2, f"应该至少有 2 个 lambda 结构体，实际 {lambda_count}"

    # 验证第一个 lambda（x + 1）
    header_pattern1 = """
    struct __lambda_${w+}_${d+}_${d+}
        : public mcpy::lambda_base<__lambda_${w+}_${d+}_${d+}, mc::variant(mc::variant)> {
        static constexpr std::array<const char*, 1> get_param_names() {
            return {"x"};
        }
        template <typename T0>
        auto operator()(T0&& x) const {
            return x + 1;
        }
    };
    """
    assert_code_contains(hpp, header_pattern1, use_markers=True)

    # 验证实现文件：列表构造
    cpp_pattern = r"""
    (mc::variants|mc::array<mc::variant>) get_funcs\(\) \{
    return (mc::variants|mc::array<mc::variant>)\{mc::variant\(mc::make_shared<__lambda_\w+_\d+_\d+>\(\)\), mc::variant\(mc::make_shared<__lambda_\w+_\d+_\d+>\(\)\)\};
    \}
    """
    assert_code_contains(cpp, cpp_pattern, use_regex=True)


def test_lambda_default_param():
    """测试带默认参数的 lambda"""

    code = """
def use_default():
    multiply = lambda x, y=2: x * y
    return multiply(5)
"""

    hpp, cpp = compile_source(code)

    # 验证头文件：带默认参数的 lambda 结构体（使用 set_defaults 机制）
    header_pattern = """
    struct __lambda_${w+}_${d+}_${d+}
        : public mcpy::lambda_base<__lambda_${w+}_${d+}_${d+}, mc::variant(mc::variant, int)> {
        static constexpr std::array<const char*, 2> get_param_names() {
            return {"x", "y"};
        }
        __lambda_${w+}_${d+}_${d+}() {
            set_defaults({mc::variant(2)}, 1);
        }
        template <typename T0>
        auto operator()(T0&& x, int y) const {
            return x * y;
        }
    };
    """
    assert_code_contains(hpp, header_pattern, use_markers=True)

    # 验证实现文件：函数调用
    cpp_pattern = """
    mc::variant use_default() {
        __lambda_${w+}_${d+}_${d+} multiply;
        return mcpy::call(multiply, 5);
    }
    """
    assert_code_contains(cpp, cpp_pattern, use_markers=True)


def test_lambda_immediate_call():
    """测试立即调用的 lambda"""

    code = """
def immediate():
    return (lambda x: x + 1)(5)
"""

    hpp, cpp = compile_source(code)

    # 验证实现文件：立即调用优化为 C++ lambda 表达式
    cpp_pattern = """
    mc::variant immediate() {
        return [](const mc::variant& x) {
            return x + 1;
        }(5);
    }
    """
    assert_code_contains(cpp, cpp_pattern)


def test_multiple_lambdas_in_function():
    """测试函数内多个 lambda"""

    code = """
def use_multiple():
    add = lambda x: x + 1
    mul = lambda x: x * 2
    return add(5) + mul(3)
"""

    hpp, cpp = compile_source(code)

    # 验证头文件包含多个 lambda 结构体
    lambda_count = hpp.count("struct __lambda_")
    assert lambda_count >= 2, f"应该至少有 2 个 lambda 结构体，实际 {lambda_count}"

    # 验证实现文件：函数使用两个 lambda
    cpp_pattern = """
    mc::variant use_multiple() {
    __lambda_${w+}_${d+}_${d+} add;
    __lambda_${w+}_${d+}_${d+} mul;
    return add(5) + mul(3);
    }
    """
    assert_code_contains(cpp, cpp_pattern, use_markers=True)


# ============================================================================
# Callable 协议测试
# ============================================================================


def test_callable_protocol_parameter():
    """测试 Callable 协议参数"""

    code = """
from typing import Callable

def apply_func(f: Callable[[int], int], x: int) -> int:
    return f(x)
"""

    hpp, cpp = compile_source(code)

    # 验证头文件：函数声明
    header_expected = """
    int apply_func(const mc::variant& f, int x);
    """
    assert_code_contains(hpp, header_expected)

    # 验证实现文件：完整的函数代码块
    cpp_expected = """
    int apply_func(const mc::variant& f, int x) {
        return mcpy::call<int>(f, x);
    }
    """
    assert_code_contains(cpp, cpp_expected)


def test_callable_protocol_return_type():
    """测试 Callable 协议返回类型"""

    code = """
from typing import Callable

def make_adder(x: int) -> Callable[[int], int]:
    return lambda y: x + y
"""

    hpp, cpp = compile_source(code)

    # 验证头文件：lambda 结构体（带闭包，类型推导为 int(int)）
    header_pattern = """
    struct __lambda_${w+}_${d+}_${d+}
        : public mcpy::lambda_base<__lambda_${w+}_${d+}_${d+}, int(int)> {
        static constexpr std::array<const char*, 1> get_param_names() {
            return {"y"};
        }
        int x;
        __lambda_${w+}_${d+}_${d+}(int x_)
            : x(std::move(x_)) {
        }
        auto operator()(int y) const {
            return x + y;
        }
    };
    """
    assert_code_contains(hpp, header_pattern, use_markers=True)

    # 验证实现文件：函数返回 mc::variant
    cpp_expected = """
    mc::variant make_adder(int x) {
        return mc::variant(mc::make_shared<__lambda_${w+}_${d+}_${d+}>(x));
    }
    """
    assert_code_contains(cpp, cpp_expected, use_markers=True)


def test_callable_with_closure():
    """测试带闭包的 Callable 返回值"""

    code = """
from typing import Callable

def make_adder(base: int) -> Callable[[int], int]:
    return lambda x: x + base
"""

    hpp, cpp = compile_source(code)

    # 验证头文件：闭包 lambda 结构体（根据实际生成的代码）
    header_pattern = """
    struct __lambda_${w+}_${d+}_${d+}
    : public mcpy::lambda_base<__lambda_${w+}_${d+}_${d+}, int(int)> {
    static constexpr std::array<const char*, 1> get_param_names() {
    return {"x"};
    }
    int base;
    __lambda_${w+}_${d+}_${d+}(int base_)
    : base(std::move(base_)) {
    }
    auto operator()(int x) const {
    return x + base;
    }
    };
    """
    assert_code_contains(hpp, header_pattern, use_markers=True)

    # 验证实现文件：函数返回 mc::variant
    cpp_pattern = """
    mc::variant make_adder(int base) {
        return mc::variant(mc::make_shared<__lambda_${w+}_${d+}_${d+}>(base));
    }
    """
    assert_code_contains(cpp, cpp_pattern, use_markers=True)


def test_callable_double_params():
    """测试双参数 Callable"""

    code = """
from typing import Callable

def call_binary(f: Callable[[int, int], int], a: int, b: int) -> int:
    return f(a, b)

def use_it() -> int:
    add_nums = lambda x, y: x + y
    return call_binary(add_nums, 3, 4)
"""

    hpp, cpp = compile_source(code)

    # 验证完整的函数代码块
    expected_call = """
    int call_binary(const mc::variant& f, int a, int b) {
        return mcpy::call<int>(f, a, b);
    }
    """
    assert_code_contains(cpp, expected_call)

    # 验证调用代码
    use_pattern = """
    int use_it() {
        mc::variant add_nums = mc::variant(mc::make_shared<__lambda_${w+}_${d+}_${d+}>());
        return call_binary(add_nums, 3, 4);
    }
    """
    assert_code_contains(cpp, use_pattern, use_markers=True)


def test_callable_nested_call():
    """测试嵌套 Callable 调用"""

    code = """
from typing import Callable

def call_twice(f: Callable[[int], int], x: int) -> int:
    return f(f(x))

def use_twice() -> int:
    increment = lambda n: n + 1
    return call_twice(increment, 10)
"""

    hpp, cpp = compile_source(code)

    # 验证完整的函数实现
    expected_func = """
    int call_twice(const mc::variant& f, int x) {
        return mcpy::call<int>(f, mcpy::call<int>(f, x));
    }
    """
    assert_code_contains(cpp, expected_func)

    # 验证调用代码
    use_pattern = """
    int use_twice() {
        mc::variant increment = mc::variant(mc::make_shared<__lambda_${w+}_${d+}_${d+}>());
        return call_twice(increment, 10);
    }
    """
    assert_code_contains(cpp, use_pattern, use_markers=True)


def test_callable_mixed_concrete_types():
    """测试 Callable 与具体类型混合"""

    code = """
from typing import Callable

def apply_to_int(func: Callable[[int], int], base_value: int) -> int:
    return func(base_value * 2)

def caller() -> int:
    doubler = lambda n: n * 2
    return apply_to_int(doubler, 5)
"""

    hpp, cpp = compile_source(code)

    # 验证头文件：函数声明
    header_expected = """
    int apply_to_int(const mc::variant& func, int base_value);
    int caller();
    """
    assert_code_contains(hpp, header_expected)

    # 验证实现文件：完整的函数实现
    cpp_expected = """
    int apply_to_int(const mc::variant& func, int base_value) {
        return mcpy::call<int>(func, base_value * 2);
    }
    """
    assert_code_contains(cpp, cpp_expected)

    # 验证调用代码（使用堆 lambda）
    caller_pattern = """
    int caller() {
        mc::variant doubler = mc::variant(mc::make_shared<__lambda_${w+}_${d+}_${d+}>());
        return apply_to_int(doubler, 5);
    }
    """
    assert_code_contains(cpp, caller_pattern, use_markers=True)


# ============================================================================
# TypeVar 模板参数测试
# ============================================================================


def test_typevar_basic_template():
    """测试基本 TypeVar 模板函数"""

    code = """
from typing import TypeVar

T = TypeVar('T')

def identity(x: T) -> T:
    return x

def use_identity() -> int:
    return identity(42)
"""

    hpp, cpp = compile_source(code)

    # 验证头文件：模板声明
    header_expected = """
    template <typename T>
    T identity(const T& x);
    """
    assert_code_contains(hpp, header_expected)

    # 验证实现文件：模板实现
    cpp_expected = """
    template <typename T>
    T identity(const T& x) {
        return x;
    }
    """
    assert_code_contains(cpp, cpp_expected)

    # 验证调用代码（C++ 可以自动推导模板参数）
    use_expected = """
    int use_identity() {
        return identity(42);
    }
    """
    assert_code_contains(cpp, use_expected)


def test_typevar_multiple_params():
    """测试多个 TypeVar 参数"""

    code = """
from typing import TypeVar

T = TypeVar('T')
U = TypeVar('U')

def pair_first(x: T, y: U) -> T:
    return x

def use_pair() -> int:
    return pair_first(42, "text")
"""

    hpp, cpp = compile_source(code)

    # 验证头文件：模板声明
    header_expected = """
    template <typename T, typename U>
    T pair_first(const T& x, const U& y);
    """
    assert_code_contains(hpp, header_expected)

    # 验证实现文件：模板实现
    cpp_expected = """
    template <typename T, typename U>
    T pair_first(const T& x, const U& y) {
        return x;
    }
    """
    assert_code_contains(cpp, cpp_expected)

    # 验证调用（C++ 可以自动推导模板参数）
    use_expected = """
    int use_pair() {
        return pair_first(42, "text");
    }
    """
    assert_code_contains(cpp, use_expected)


def test_typevar_multiple_uses():
    """测试同一个 TypeVar 多次使用"""

    code = """
from typing import TypeVar

T = TypeVar('T')

def use_three_times(a: T, b: T, c: T) -> T:
    return a
"""

    hpp, cpp = compile_source(code)

    # 验证模板声明
    header_expected = """
    template <typename T>
    T use_three_times(const T& a, const T& b, const T& c);
    """
    assert_code_contains(hpp, header_expected)

    # 验证三个参数都是 const T&
    cpp_expected = """
    template <typename T>
    T use_three_times(const T& a, const T& b, const T& c) {
        return a;
    }
    """
    assert_code_contains(cpp, cpp_expected)


# ============================================================================
# TypeVar + Callable 混合测试
# ============================================================================


def test_typevar_callable_mixed_template():
    """测试 TypeVar + Callable 混合模板"""

    code = """
from typing import TypeVar, Callable

T = TypeVar('T')
R = TypeVar('R')

def apply(f: Callable[[T], R], x: T) -> R:
    return f(x)

def use_apply() -> int:
    add_1 = lambda x: x + 1
    result: int = apply(add_1, 5)
    return result
"""

    hpp, cpp = compile_source(code)

    # 验证头文件：模板声明（R 在前，T 在后）
    header_pattern = """
    template <typename R, typename T>
    R apply(const mc::variant& f, const T& x);
    """
    assert_code_contains(hpp, header_pattern)

    # 验证实现文件：模板函数
    cpp_expected = """
    template <typename R, typename T>
    R apply(const mc::variant& f, const T& x) {
        return mcpy::call<R>(f, x);
    }
    """
    assert_code_contains(cpp, cpp_expected)

    # 验证调用：显式模板参数
    use_pattern = """
    int use_apply() {
        mc::variant add_1 = mc::variant(mc::make_shared<__lambda_${w+}_${d+}_${d+}>());
        int result = apply<int>(add_1, 5);
        return result;
    }
    """
    assert_code_contains(cpp, use_pattern, use_markers=True)


def test_typevar_callable_nested():
    """测试嵌套 Callable 调用（单 TypeVar）"""

    code = """
from typing import TypeVar, Callable

T = TypeVar('T')

def apply_twice(f: Callable[[T], T], x: T) -> T:
    return f(f(x))

def use_twice() -> int:
    add_1 = lambda x: x + 1
    return apply_twice(add_1, 5)
"""

    hpp, cpp = compile_source(code)

    # 验证头文件：模板声明
    header_expected = """
    template <typename T>
    T apply_twice(const mc::variant& f, const T& x);
    """
    assert_code_contains(hpp, header_expected)

    # 验证实现文件：模板函数实现（嵌套的 mcpy::call）
    cpp_expected = """
    template <typename T>
    T apply_twice(const mc::variant& f, const T& x) {
        return mcpy::call<T>(f, mcpy::call<T>(f, x));
    }
    """
    assert_code_contains(cpp, cpp_expected)

    # 验证调用代码（使用堆 lambda）
    use_pattern = """
    int use_twice() {
        mc::variant add_1 = mc::variant(mc::make_shared<__lambda_${w+}_${d+}_${d+}>());
        return apply_twice(add_1, 5);
    }
    """
    assert_code_contains(cpp, use_pattern, use_markers=True)


def test_typevar_callable_with_non_typevar_return():
    """测试 Callable 返回固定类型（非 TypeVar）"""

    code = """
from typing import TypeVar, Callable

T = TypeVar('T')

def process(f: Callable[[T], int], x: T) -> int:
    return f(x)
"""

    hpp, cpp = compile_source(code)

    # 验证头文件：模板声明（返回固定 int 类型）
    header_expected = """
    template <typename T>
    int process(const mc::variant& f, const T& x);
    """
    assert_code_contains(hpp, header_expected)

    # 验证实现文件：模板函数实现
    cpp_expected = """
    template <typename T>
    int process(const mc::variant& f, const T& x) {
        return mcpy::call<int>(f, x);
    }
    """
    assert_code_contains(cpp, cpp_expected)


def test_typevar_return_priority():
    """测试返回值 TypeVar 优先排序"""

    code = """
from typing import TypeVar, Callable

Input = TypeVar('Input')
Output = TypeVar('Output')

def transform(mapper: Callable[[Input], Output], value: Input) -> Output:
    return mapper(value)
"""

    hpp, cpp = compile_source(code)

    # 验证头文件：模板声明（Output 在 Input 之前，保留原始 TypeVar 名称）
    header_expected = """
    template <typename Output, typename Input>
    Output transform(const mc::variant& mapper, const Input& value);
    """
    assert_code_contains(hpp, header_expected)

    # 验证实现文件：模板函数实现
    cpp_expected = """
    template <typename Output, typename Input>
    Output transform(const mc::variant& mapper, const Input& value) {
        return mcpy::call<Output>(mapper, value);
    }
    """
    assert_code_contains(cpp, cpp_expected)


def test_typevar_callable_integration():
    """测试 TypeVar + Callable 集成场景"""

    code = """
from typing import TypeVar, Callable

T = TypeVar('T')
R = TypeVar('R')

def chain_apply(f: Callable[[T], R], g: Callable[[R], R], x: T) -> R:
    return g(f(x))

def use_chain() -> int:
    add_one = lambda x: x + 1
    double = lambda x: x * 2
    return chain_apply(add_one, double, 5)
"""

    hpp, cpp = compile_source(code)

    # 验证头文件：模板声明
    header_expected = """
    template <typename R, typename T>
    R chain_apply(const mc::variant& f, const mc::variant& g, const T& x);
    """
    assert_code_contains(hpp, header_expected)

    # 验证实现文件：模板函数实现（嵌套 mcpy::call）
    cpp_expected = """
    template <typename R, typename T>
    R chain_apply(const mc::variant& f, const mc::variant& g, const T& x) {
        return mcpy::call<R>(g, mcpy::call<R>(f, x));
    }
    """
    assert_code_contains(cpp, cpp_expected)

    # 验证调用代码（使用堆 lambda，注意对齐）
    use_pattern = """
    int use_chain() {
        mc::variant add_one = mc::variant(mc::make_shared<__lambda_${w+}_${d+}_${d+}>());
        mc::variant double${s+}= mc::variant(mc::make_shared<__lambda_${w+}_${d+}_${d+}>());
        return chain_apply(add_one, double, 5);
    }
    """
    assert_code_contains(cpp, use_pattern, use_markers=True)


# ============================================================================
# 类型安全检查测试
# ============================================================================


def test_type_mismatch_one_vs_two_params():
    """测试编译时类型检查：1 参数 vs 2 参数不匹配"""

    code = """
from typing import TypeVar, Callable

T = TypeVar('T')

def apply_once(f: Callable[[T], T], x: T) -> T:
    return f(x)

def test_error():
    two_params = lambda x, y: x + y
    return apply_once(two_params, 5)
"""

    with pytest.raises(Exception) as exc_info:
        hpp, cpp = compile_source(code)

    error_msg = str(exc_info.value)
    assert "类型不匹配" in error_msg
    assert "参数" in error_msg


def test_type_mismatch_zero_vs_one_param():
    """测试类型安全：0 参数 vs 1 参数不匹配"""

    code = """
from typing import Callable

def requires_one_param(f: Callable[[int], int]) -> int:
    return f(42)

def test_error():
    no_param_func = lambda: 100
    return requires_one_param(no_param_func)
"""

    with pytest.raises(Exception) as exc_info:
        hpp, cpp = compile_source(code)

    error_msg = str(exc_info.value)
    assert "类型不匹配" in error_msg
    assert "0 个参数" in error_msg or "1 个参数" in error_msg


def test_type_mismatch_two_vs_one_param():
    """测试类型安全：2 参数 vs 1 参数不匹配"""

    code = """
from typing import Callable

def requires_one(f: Callable[[int], int]) -> int:
    return f(10)

def test_error():
    two_param_func = lambda a, b: a + b
    return requires_one(two_param_func)
"""

    with pytest.raises(Exception) as exc_info:
        hpp, cpp = compile_source(code)

    error_msg = str(exc_info.value)
    assert "类型不匹配" in error_msg
    assert "1 个参数" in error_msg or "2 个参数" in error_msg


def test_callable_correct_match():
    """测试类型匹配正确的情况"""

    code = """
from typing import Callable

def apply_correctly(f: Callable[[int], int], x: int) -> int:
    return f(x)

def use_correctly() -> int:
    increment = lambda n: n + 1
    return apply_correctly(increment, 10)
"""

    hpp, cpp = compile_source(code)

    # 验证头文件：函数声明
    header_expected = """
    int apply_correctly(const mc::variant& f, int x);
    int use_correctly();
    """
    assert_code_contains(hpp, header_expected)

    # 验证实现文件：函数实现
    cpp_expected = """
    int apply_correctly(const mc::variant& f, int x) {
        return mcpy::call<int>(f, x);
    }
    """
    assert_code_contains(cpp, cpp_expected)

    # 验证调用代码（使用堆 lambda）
    use_pattern = """
    int use_correctly() {
        mc::variant increment = mc::variant(mc::make_shared<__lambda_${w+}_${d+}_${d+}>());
        return apply_correctly(increment, 10);
    }
    """
    assert_code_contains(cpp, use_pattern, use_markers=True)


def test_callable_protocol_type_safety():
    """测试 Callable 协议的类型安全（综合）"""

    # 正确的情况
    code_ok = """
from typing import Callable

def apply(f: Callable[[int, str], bool], a: int, b: str) -> bool:
    return f(a, b)

def use_it():
    checker = lambda num, text: num > 0 and len(text) > 0
    return apply(checker, 5, "hello")
"""

    hpp_ok, cpp_ok = compile_source(code_ok)

    # 验证编译成功：函数实现（字符串参数推导为 std::string）
    cpp_ok_expected = """
    bool apply(const mc::variant& f, int a, const std::string& b) {
        return mcpy::call<bool>(f, a, b);
    }
    """
    assert_code_contains(cpp_ok, cpp_ok_expected)

    # 错误的情况：参数数量不匹配
    code_err = """
from typing import Callable

def apply_binary(f: Callable[[int, int], int]) -> int:
    return f(1, 2)

def test_err():
    unary = lambda x: x + 1
    return apply_binary(unary)
"""

    with pytest.raises(Exception) as exc_info:
        hpp_err, cpp_err = compile_source(code_err)

    error_msg = str(exc_info.value)
    assert "类型不匹配" in error_msg


# ============================================================================
# 显式模板参数生成测试
# ============================================================================


def test_explicit_template_args_for_callable():
    """测试 Callable 参数时生成显式模板参数"""

    code = """
from typing import TypeVar, Callable

T = TypeVar('T')
R = TypeVar('R')

def mapper(f: Callable[[T], R], x: T) -> R:
    return f(x)

def use_mapper() -> int:
    add_1 = lambda x: x + 1
    result: int = mapper(add_1, 5)
    return result
"""

    hpp, cpp = compile_source(code)

    # 验证头文件：模板声明
    header_expected = """
    template <typename R, typename T>
    R mapper(const mc::variant& f, const T& x);
    """
    assert_code_contains(hpp, header_expected)

    # 验证实现文件：模板函数实现
    cpp_expected = """
    template <typename R, typename T>
    R mapper(const mc::variant& f, const T& x) {
        return mcpy::call<R>(f, x);
    }
    """
    assert_code_contains(cpp, cpp_expected)

    # 验证调用代码：生成显式模板参数（使用堆 lambda，注意对齐）
    use_pattern = """
    int use_mapper() {
        mc::variant add_1${s+}= mc::variant(mc::make_shared<__lambda_${w+}_${d+}_${d+}>());
        int${s+}result = mapper<int>(add_1, 5);
        return result;
    }
    """
    assert_code_contains(cpp, use_pattern, use_markers=True)


def test_lambda_parameter_names():
    """测试 lambda 参数名称保留"""

    code = """
def use_named_params():
    compute = lambda width, height: width * height
    return compute(10, 20)
"""

    hpp, cpp = compile_source(code)

    # 验证头文件：lambda 结构体保留参数名
    header_pattern = """
    struct __lambda_${w+}_${d+}_${d+}
        : public mcpy::lambda_base<__lambda_${w+}_${d+}_${d+}, mc::variant(mc::variant, mc::variant)> {
        static constexpr std::array<const char*, 2> get_param_names() {
            return {"width", "height"};
        }
        template <typename T0, typename T1>
        auto operator()(T0&& width, T1&& height) const {
            return width * height;
        }
    };
    """
    assert_code_contains(hpp, header_pattern, use_markers=True)

    # 验证实现文件：函数调用
    cpp_pattern = """
    mc::variant use_named_params() {
        __lambda_${w+}_${d+}_${d+} compute;
        return compute(10, 20);
    }
    """
    assert_code_contains(cpp, cpp_pattern, use_markers=True)


def test_typevar_without_callable_params():
    """测试纯 TypeVar 函数（无 Callable 参数）"""

    code = """
from typing import TypeVar

T = TypeVar('T')

def swap_first(x: T, y: T) -> T:
    return x
"""

    hpp, cpp = compile_source(code)

    # 验证头文件：模板声明
    header_expected = """
    template <typename T>
    T swap_first(const T& x, const T& y);
    """
    assert_code_contains(hpp, header_expected)

    # 验证实现文件：模板函数实现
    cpp_expected = """
    template <typename T>
    T swap_first(const T& x, const T& y) {
        return x;
    }
    """
    assert_code_contains(cpp, cpp_expected)


def test_multiple_typevar_independence():
    """测试多个 TypeVar 的独立性"""

    code = """
from typing import TypeVar

T = TypeVar('T')
U = TypeVar('U')

def combine(x: T, y: U) -> T:
    return x
"""

    hpp, cpp = compile_source(code)

    # 验证头文件：模板声明（两个独立的 TypeVar）
    header_expected = """
    template <typename T, typename U>
    T combine(const T& x, const U& y);
    """
    assert_code_contains(hpp, header_expected)

    # 验证实现文件：模板函数实现
    cpp_expected = """
    template <typename T, typename U>
    T combine(const T& x, const U& y) {
        return x;
    }
    """
    assert_code_contains(cpp, cpp_expected)
